﻿using iTool_Cetector.Controllers;
using iTool_Cetector.Global;
using iTool_Cetector.Result;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;

namespace iTool_Cetector
{
    public class GlobalStatus
    {

        private readonly System.Timers.Timer iTimer;
        private int inSubmitLinuxStatus = 0;
        private int inSubmitProcessIndex = 0;
        private bool GetInstancesStatus = false;
        public List<InstanceOptions> Instances;

        /// <summary>
        /// 是否成功联系上网关
        /// </summary>
        public bool IsSuccessfullyCallGateway { get; set; }
        public DateTime LastCallFatewayTime { get; set; }
        public DateTime StartUpTime { get; set; } = DateTime.Now;
        public bool LastCallFatewayIsSuccessfully { get; set; }
        private bool _IniInstances { get; set; }
        public bool IniInstances
        {
            get { return _IniInstances; }
            set
            {
                _IniInstances = value;
                if (!value)
                {
                    Instances = new List<InstanceOptions>();
                }
            }
        }

        public GlobalStatus()
        {
            iTimer = new System.Timers.Timer();
            iTimer.Elapsed += new System.Timers.ElapsedEventHandler((sender, args) => TimerMethod());
            iTimer.Interval = 3000;
            iTimer.AutoReset = true;
            iTimer.Enabled = true;
        }

        public async void TimerMethod()
        {
            //Utils.Logger($"Start TimerMethod: {DateTime.Now},{inSubmitLinuxStatus},{LastCallFatewayIsSuccessfully},{GlobalUtils.SeedString}");

            try
            {
                if (Interlocked.Exchange(ref inSubmitLinuxStatus, 1) == 0)
                {
                    //Utils.Logger($"Invoke TimerMethod: {DateTime.Now}");

                    await SubmitLinuxStatus();

                    // 获取 Config
                    await this.GetiToolConfigure();

                    // 获取 Instances
                    await this.GetInstances();

                    if (inSubmitProcessIndex % 2 == 1 & Instances?.Count > 0)
                    {
                        foreach (var item in Instances)
                        {
                            await SubmitProcessStatus(item);
                        }
                    }

                    inSubmitProcessIndex++;

                    Interlocked.Exchange(ref inSubmitLinuxStatus, 0);
                }
            }
            catch (Exception ex)
            {
                Interlocked.Exchange(ref inSubmitLinuxStatus, 0);
                Utils.Logger($"TimerMethod Error: {JsonConvert.SerializeObject(ex)}");
            }

        }

        public object GetStatus()
        {
            return new
            {
                this.IsSuccessfullyCallGateway,
                this.LastCallFatewayIsSuccessfully,
                this.LastCallFatewayTime,
                this.StartUpTime,
                GlobalUtils.SeedString,
                GlobalUtils.PublicIp,
                GlobalUtils.GatewayUrl,
                this.Instances,
                this.GetInstancesStatus,
                this.inSubmitProcessIndex,
                this.IniInstances,
                this.inSubmitLinuxStatus,
                GlobalUtils.IsSetteriToolConfigure,
                GlobalUtils.iToolConfigure
            };
        }

        private async Task SubmitLinuxStatus()
        {
            try
            {

                LinuxController controller = new LinuxController();

                // 如上一次请求失败了， 则暂时不带参数请求
                HttpContent content = LastCallFatewayIsSuccessfully && !string.IsNullOrWhiteSpace(GlobalUtils.SeedString) ? 
                    new StringContent(JsonConvert.SerializeObject(controller.GetStatus())) 
                    : 
                    new StringContent(string.Empty);

                HttpClient httpClient = CreateHttpClientObject(content);
                var resultTask = httpClient.PostAsync($"{GlobalUtils.GatewayUrl.TrimEnd('/')}/nodestatus", content);
                resultTask.Wait(2000);

                if (resultTask.IsCompleted)
                {
                    LastCallFatewayTime = DateTime.Now;
                    LastCallFatewayIsSuccessfully = resultTask.Result.IsSuccessStatusCode;

                    // 检查是否有种子
                    if (resultTask.Result.IsSuccessStatusCode)
                    {
                        var seed = await resultTask.Result.Content.ReadAsStringAsync();
                        if (!string.IsNullOrWhiteSpace(seed) && seed.Length < 60)
                        {
                            GlobalUtils.SeedString = seed.Trim();

                            // 成功一次标识
                            if (!IsSuccessfullyCallGateway && LastCallFatewayIsSuccessfully)
                            {
                                IsSuccessfullyCallGateway = true;
                            }

                            await this.IniPluginsRepos();
                        }
                    }

                    
                }
                else
                {
                    LastCallFatewayIsSuccessfully = false;
                }

                // 强制GC
                GC.Collect();

                Interlocked.Exchange(ref inSubmitLinuxStatus, 0);
            }
            catch (Exception ex)
            {
                Interlocked.Exchange(ref inSubmitLinuxStatus, 0);
                Utils.Logger($"Error SubmitLinuxStatus:{ex.Message}");
                LastCallFatewayTime = DateTime.Now;
                LastCallFatewayIsSuccessfully = false;
            }
        }

        private async Task SubmitProcessStatus(InstanceOptions options)
        {
            if (!LastCallFatewayIsSuccessfully)
            {
                return;
            }

            try
            {
                var body = options.IsRunInDocker ?
                new DockerController(this).Status(options.Title)
                :
                new LinuxController().GetDotnetStatus(options.Title);
                body.ServiceInstanceId = options.ServiceInstanceId;
                HttpContent content = new StringContent(JsonConvert.SerializeObject(body));

                HttpClient httpClient = CreateHttpClientObject(content);
                var resultTask = httpClient.PostAsync($"{GlobalUtils.GatewayUrl.TrimEnd('/')}/processstatus", content);
                resultTask.Wait(2000);
                if (resultTask.IsCompleted)
                {
                    if (resultTask.Result.IsSuccessStatusCode)
                    {
                        GetInstancesStatus = true;
                    }
                    else
                    {
                        var contentx = await resultTask.Result.Content.ReadAsStringAsync();
                        Utils.Logger($"Error SubmitProcessStatus:{resultTask.Result.IsSuccessStatusCode},{contentx}");
                    }
                }
            }
            catch (Exception ex)
            {
                if (options.Title == "iTool-Server")
                {
                    HttpContent content = new StringContent(File.ReadAllText(iToolServiceStatusFileChange._iToolServiceProcessPath));
                    HttpClient httpClient = CreateHttpClientObject(content);
                    var result = await httpClient.PostAsync(iToolServiceStatusFileChange.serviceURL, content);
                    IniInstances = false;
                }
                else if (options.Title == "iTool-Connector")
                {
                    HttpContent content = new StringContent(File.ReadAllText(iToolServiceStatusFileChange._iToolConnectorProcessPath));
                    HttpClient httpClient = CreateHttpClientObject(content);
                    var result = await httpClient.PostAsync(iToolServiceStatusFileChange.clientURL, content);
                    IniInstances = false;

                }
                Utils.Logger($"Error SubmitProcessStatus:{JsonConvert.SerializeObject(options)},{JsonConvert.SerializeObject(ex)}");
            }
        }

        private async Task GetInstances()
        {
            if (IniInstances == false)
            {
                var content = new StringContent(string.Empty);
                var httpClient = CreateHttpClientObject(content);
                var resultTask = httpClient.PostAsync($"{GlobalUtils.GatewayUrl}/instances", content);
                resultTask.Wait(2000);
                if (resultTask.IsCompleted)
                {
                    if (resultTask.Result.IsSuccessStatusCode)
                    {
                        var body = await resultTask.Result.Content.ReadAsStringAsync();

                        if (!string.IsNullOrWhiteSpace(body))
                        {
                            var value = JsonConvert.DeserializeObject<List<InstanceOptions>>(body);

                            if (value != null)
                            {
                                Instances = value;
                                IniInstances = resultTask.Result.IsSuccessStatusCode;
                            }
                        }
                    }
                }
            }
            
        }

        private async Task GetiToolConfigure()
        {
            if (!GlobalUtils.IsSetteriToolConfigure)
            {
                var content = new StringContent(string.Empty);
                HttpClient httpClient = CreateHttpClientObject(content);
                var resultTask = httpClient.PostAsync($"{GlobalUtils.GatewayUrl}/itoolconfig", content);
                resultTask.Wait(2000);
                if (resultTask.IsCompleted)
                {
                    if (resultTask.Result.IsSuccessStatusCode)
                    {
                        var configure = await resultTask.Result.Content.ReadAsStringAsync();

                        if (!string.IsNullOrWhiteSpace(configure))
                        {
                            var value = JsonConvert.DeserializeObject<iToolConfigure>(configure);
                            if (value != null && value?.Port > 0)
                            {
                                Utils.Logger($"get itoolconfig:{configure}");
                                GlobalUtils.iToolConfigure = value;
                            }                                               
                        }
                    }
                }
            }
        }


        private async Task IniPluginsRepos()
        {
            try
            {
                await new PluginsController().Upgrade("iTool-Server-Plugins");
                await new PluginsController().Upgrade("iTool-Connector-Plugins");
            }
            catch (Exception ex)
            {
                Utils.Logger("IniPluginsRepos",ex);
            }
        }

        public async Task StopApplication() 
        {
            try
            {
                var content = new StringContent(string.Empty);
                HttpClient httpClient = CreateHttpClientObject(content);
                await httpClient.PostAsync($"{GlobalUtils.GatewayUrl}/stop", content);
            }
            catch (Exception ex)
            {
                Utils.Logger($"Error SubmitLinuxStatus:{ex.Message}");
            }
        }

        private HttpClient CreateHttpClientObject(HttpContent content) 
        {
            HttpClient httpClient = HttpClientFactory.Create();
            //content.Headers.Add("seed", GlobalUtils.SeedString);
            //content.Headers.Add("publicip", GlobalUtils.PublicIp);

            // 头部+入签名信息
            if (!string.IsNullOrWhiteSpace(GlobalUtils.SeedString))
            {
                content.Headers.Add("seed", GlobalUtils.SeedString);
            }

            content.Headers.Add("publicip", GlobalUtils.PublicIp);

            return httpClient;
        }

    }
}
